#include "TextureRenderer.h"
#include "../GameObject/GameObject.h"
#include <graphics.h>
#include <iostream>
#include <algorithm>

Camera* TextureRenderer::s_renderingCamera = nullptr;

TextureRenderer::TextureRenderer(GameObject* gameObject)
    : Component(gameObject)
    , m_textureAsset(nullptr)
    , m_currentTextureId("")
    , m_assetManager(AssetManager::GetInstance())
    , m_renderMode(RenderMode::Stretch)
    , m_textureOffsetX(0.0f)
    , m_textureOffsetY(0.0f)
    , m_textureScaleX(1.0f)
    , m_textureScaleY(1.0f)
    , m_alpha(1.0f)
    , m_tintColor(WHITE)
    , m_tintEnabled(false)
{
}

bool TextureRenderer::SetTexture(const std::string& textureId, const std::wstring& texturePath)
{
    if (!m_assetManager) {
        std::cout << "[TextureRenderer] Error: AssetManager not available" << std::endl;
        return false;
    }

    m_textureAsset = m_assetManager->CreateAsset<TextureAsset>(textureId, texturePath);
    if (!m_textureAsset) {
        std::cout << "[TextureRenderer] Error: Failed to create texture asset: " << textureId << std::endl;
        return false;
    }

    if (!m_assetManager->LoadAsset(textureId)) {
        std::cout << "[TextureRenderer] Error: Failed to load texture: " << textureId << std::endl;
        m_textureAsset = nullptr;
        return false;
    }

    m_currentTextureId = textureId;
    std::cout << "[TextureRenderer] Texture loaded successfully: " << textureId << std::endl;
    return true;
}

bool TextureRenderer::SetTexture(const std::string& textureId)
{
    if (!m_assetManager) {
        std::cout << "[TextureRenderer] Error: AssetManager not available" << std::endl;
        return false;
    }

    m_textureAsset = m_assetManager->GetAsset<TextureAsset>(textureId);
    if (!m_textureAsset) {
        std::cout << "[TextureRenderer] Error: Texture asset not found: " << textureId << std::endl;
        return false;
    }

    if (!m_textureAsset->IsLoaded()) {
        if (!m_assetManager->LoadAsset(textureId)) {
            std::cout << "[TextureRenderer] Error: Failed to load existing texture: " << textureId << std::endl;
            m_textureAsset = nullptr;
            return false;
        }
    }

    m_currentTextureId = textureId;
    std::cout << "[TextureRenderer] Using existing texture: " << textureId << std::endl;
    return true;
}

void TextureRenderer::ClearTexture()
{
    m_textureAsset = nullptr;
    m_currentTextureId = "";
}

void TextureRenderer::SetTextureOffset(float offsetX, float offsetY)
{
    m_textureOffsetX = offsetX;
    m_textureOffsetY = offsetY;
}

void TextureRenderer::SetTextureScale(float scaleX, float scaleY)
{
    m_textureScaleX = (std::max)(0.1f, scaleX);
    m_textureScaleY = (std::max)(0.1f, scaleY);
}

void TextureRenderer::SetAlpha(float alpha)
{
    m_alpha = (std::max)(0.0f, (std::min)(1.0f, alpha));
}

void TextureRenderer::render()
{
    if (!enabled_ || !HasValidTexture()) return;

    Transform* transform = gameObject_->getTransform();
    if (!transform) return;

    // 根据渲染模式进行渲染
    switch (m_renderMode) {
    case RenderMode::Stretch:
        RenderStretched();
        break;
    case RenderMode::Tile:
        RenderTiled();
        break;
    case RenderMode::Center:
        RenderCentered();
        break;
    case RenderMode::FitWidth:
        RenderFitWidth();
        break;
    case RenderMode::FitHeight:
        RenderFitHeight();
        break;
    case RenderMode::KeepRatio:
        RenderKeepRatio();
        break;
    }
}

bool TextureRenderer::HasValidTexture() const
{
    return m_textureAsset && m_textureAsset->IsLoaded() && m_textureAsset->GetImage();
}

int TextureRenderer::GetTextureWidth() const
{
    if (!HasValidTexture()) return 0;
    return m_textureAsset->GetWidth();
}

int TextureRenderer::GetTextureHeight() const
{
    if (!HasValidTexture()) return 0;
    return m_textureAsset->GetHeight();
}

void TextureRenderer::RenderStretched()
{
    Transform* transform = gameObject_->getTransform();
    IMAGE* image = m_textureAsset->GetImage();

    float worldX = transform->getX();
    float worldY = transform->getY();
    float width = transform->getWidth();
    float height = transform->getHeight();

    float screenX = worldX;
    float screenY = worldY;

    if (s_renderingCamera) {
        screenX = s_renderingCamera->worldToScreenX(worldX);
        screenY = s_renderingCamera->worldToScreenY(worldY);
    }

    RenderImage(image, static_cast<int>(screenX), static_cast<int>(screenY), 
                static_cast<int>(width), static_cast<int>(height));
}

void TextureRenderer::RenderTiled()
{
    Transform* transform = gameObject_->getTransform();
    IMAGE* image = m_textureAsset->GetImage();

    float worldX = transform->getX();
    float worldY = transform->getY();
    float width = transform->getWidth();
    float height = transform->getHeight();

    float screenX = worldX;
    float screenY = worldY;

    if (s_renderingCamera) {
        screenX = s_renderingCamera->worldToScreenX(worldX);
        screenY = s_renderingCamera->worldToScreenY(worldY);
    }

    RenderImageTiled(image, static_cast<int>(screenX), static_cast<int>(screenY), 
                     static_cast<int>(width), static_cast<int>(height));
}

void TextureRenderer::RenderCentered()
{
    Transform* transform = gameObject_->getTransform();
    IMAGE* image = m_textureAsset->GetImage();

    int texWidth = GetTextureWidth();
    int texHeight = GetTextureHeight();

    float worldX = transform->getX();
    float worldY = transform->getY();
    float width = transform->getWidth();
    float height = transform->getHeight();

    float centeredX = worldX + (width - texWidth) / 2.0f;
    float centeredY = worldY + (height - texHeight) / 2.0f;

    float screenX = centeredX;
    float screenY = centeredY;

    if (s_renderingCamera) {
        screenX = s_renderingCamera->worldToScreenX(centeredX);
        screenY = s_renderingCamera->worldToScreenY(centeredY);
    }

    RenderImage(image, static_cast<int>(screenX), static_cast<int>(screenY), texWidth, texHeight);
}

void TextureRenderer::RenderFitWidth()
{
    Transform* transform = gameObject_->getTransform();
    IMAGE* image = m_textureAsset->GetImage();

    int texWidth = GetTextureWidth();
    int texHeight = GetTextureHeight();

    if (texWidth == 0) return;

    float worldX = transform->getX();
    float worldY = transform->getY();
    float width = transform->getWidth();
    float height = transform->getHeight();

    float scale = width / texWidth;
    int newWidth = static_cast<int>(width);
    int newHeight = static_cast<int>(texHeight * scale);

    float centeredY = worldY + (height - newHeight) / 2.0f;

    float screenX = worldX;
    float screenY = centeredY;

    if (s_renderingCamera) {
        screenX = s_renderingCamera->worldToScreenX(worldX);
        screenY = s_renderingCamera->worldToScreenY(centeredY);
    }

    RenderImage(image, static_cast<int>(screenX), static_cast<int>(screenY), newWidth, newHeight);
}

void TextureRenderer::RenderFitHeight()
{
    Transform* transform = gameObject_->getTransform();
    IMAGE* image = m_textureAsset->GetImage();

    int texWidth = GetTextureWidth();
    int texHeight = GetTextureHeight();

    if (texHeight == 0) return;

    float worldX = transform->getX();
    float worldY = transform->getY();
    float width = transform->getWidth();
    float height = transform->getHeight();

    float scale = height / texHeight;
    int newWidth = static_cast<int>(texWidth * scale);
    int newHeight = static_cast<int>(height);

    float centeredX = worldX + (width - newWidth) / 2.0f;

    float screenX = centeredX;
    float screenY = worldY;

    if (s_renderingCamera) {
        screenX = s_renderingCamera->worldToScreenX(centeredX);
        screenY = s_renderingCamera->worldToScreenY(worldY);
    }

    RenderImage(image, static_cast<int>(screenX), static_cast<int>(screenY), newWidth, newHeight);
}

void TextureRenderer::RenderKeepRatio()
{
    Transform* transform = gameObject_->getTransform();
    IMAGE* image = m_textureAsset->GetImage();

    int texWidth = GetTextureWidth();
    int texHeight = GetTextureHeight();

    if (texWidth == 0 || texHeight == 0) return;

    float worldX = transform->getX();
    float worldY = transform->getY();
    float width = transform->getWidth();
    float height = transform->getHeight();

    float scaleX = width / texWidth;
    float scaleY = height / texHeight;
    float scale = (std::min)(scaleX, scaleY);

    int newWidth = static_cast<int>(texWidth * scale);
    int newHeight = static_cast<int>(texHeight * scale);

    float centeredX = worldX + (width - newWidth) / 2.0f;
    float centeredY = worldY + (height - newHeight) / 2.0f;

    float screenX = centeredX;
    float screenY = centeredY;

    if (s_renderingCamera) {
        screenX = s_renderingCamera->worldToScreenX(centeredX);
        screenY = s_renderingCamera->worldToScreenY(centeredY);
    }

    RenderImage(image, static_cast<int>(screenX), static_cast<int>(screenY), newWidth, newHeight);
}

void TextureRenderer::RenderImage(IMAGE* image, int x, int y, int width, int height)
{
    if (!image) return;

    HDC srcDC = GetImageHDC(image);
    HDC destDC = GetImageHDC();

    if (srcDC && destDC) {
        StretchBlt(destDC, x, y, width, height, srcDC, 0, 0, image->getwidth(), image->getheight(), SRCCOPY);
    }
}

void TextureRenderer::RenderImageTiled(IMAGE* image, int x, int y, int width, int height)
{
    if (!image) return;

    int texWidth = static_cast<int>(GetTextureWidth() * m_textureScaleX);
    int texHeight = static_cast<int>(GetTextureHeight() * m_textureScaleY);

    if (texWidth <= 0 || texHeight <= 0) return;

    int startX = x + static_cast<int>(m_textureOffsetX) % texWidth;
    int startY = y + static_cast<int>(m_textureOffsetY) % texHeight;

    if (startX > x) startX -= texWidth;
    if (startY > y) startY -= texHeight;

    for (int tileY = startY; tileY < y + height; tileY += texHeight) {
        for (int tileX = startX; tileX < x + width; tileX += texWidth) {
            int renderX = (std::max)(tileX, x);
            int renderY = (std::max)(tileY, y);
            int renderWidth = (std::min)(tileX + texWidth, x + width) - renderX;
            int renderHeight = (std::min)(tileY + texHeight, y + height) - renderY;

            if (renderWidth > 0 && renderHeight > 0) {
                int srcX = renderX - tileX;
                int srcY = renderY - tileY;
                int srcWidth = static_cast<int>(renderWidth / m_textureScaleX);
                int srcHeight = static_cast<int>(renderHeight / m_textureScaleY);

                HDC srcDC = GetImageHDC(image);
                HDC destDC = GetImageHDC();

                if (srcDC && destDC) {
                    StretchBlt(destDC, renderX, renderY, renderWidth, renderHeight,
                        srcDC, srcX, srcY, srcWidth, srcHeight, SRCCOPY);

                }
            }
        }
    }
}
